﻿using System;
using OpenTK;
using OpenTK.Graphics.OpenGL;

namespace Jayden.Dll.OpenGL
{
	public class Helper
	{

		public static void Normal(Vector3 a, Vector3 b, Vector3 c)
		{
			Vector3 dir = Vector3.Cross(b - a, c - a);
			Vector3 norm = Vector3.Normalize(dir);
			GL.Normal3(norm);
		}
		public static void Normal(Vector3d a, Vector3d b, Vector3d c)
		{
			Vector3d dir = Vector3d.Cross(b - a, c - a);
			Vector3d norm = Vector3d.Normalize(dir);
			GL.Normal3(norm);
		}

		public static void Sphere() { Sphere(1.0, 16, 16); }
		public static void Sphere(double size, int slices, int stacks)
		{
			double radius = size / 2.0;
			double[] sin = new double[slices];
			double[] cos = new double[slices];
			double[] rad = new double[stacks + 1];
			double[] ys = new double[stacks + 1];


			for (int slice = 0; slice < slices; slice++)
			{
				double x = slice * (Math.PI * 2.0) / (double)slices;
				sin[slice] = Math.Sin(x);
				cos[slice] = Math.Cos(x);
			}

			for (int stack = 0; stack < stacks; stack++)
			{
				double y = stack * Math.PI / (double)stacks;
				rad[stack] = Math.Sin(y);
				ys[stack] = Math.Cos(y);
			}
			rad[stacks] = 0;
			ys[stacks] = -1;

			Vector3d normal;

			for (int stack = 0; stack < stacks; stack++)
			{
				double yTextureBot = stack / (double)stacks;
				double yTextureTop = (stack + 1) / (double)stacks;
				GL.Begin(BeginMode.QuadStrip);
				double radiusBot = rad[stack] * radius;
				double radiusTop = rad[stack + 1] * radius;
				double yBot = ys[stack] * radius;
				double yTop = ys[stack + 1] * radius;
				for (int slice = 0; slice < slices; slice++)
				{
					double xTexture = slice / (double)slices;

					normal = new Vector3d(sin[slice] * rad[stack], ys[stack], cos[slice] * rad[stack]);
					GL.Normal3(normal);
					GL.TexCoord2(xTexture, yTextureBot);
					GL.Vertex3(sin[slice] * radiusBot, yBot, cos[slice] * radiusBot);

					normal = new Vector3d(sin[slice] * rad[stack + 1], ys[stack + 1], cos[slice] * rad[stack + 1]);
					GL.Normal3(normal);
					GL.TexCoord2(xTexture, yTextureTop);
					GL.Vertex3(sin[slice] * radiusTop, yTop, cos[slice] * radiusTop);
				}
				normal = new Vector3d(sin[0] * rad[stack], ys[stack], cos[0] * rad[stack]);
				GL.Normal3(normal);
				GL.TexCoord2(1, yTextureBot);
				GL.Vertex3(sin[0] * radiusBot, yBot, cos[0] * radiusBot);

				normal = new Vector3d(sin[0] * rad[stack + 1], ys[stack + 1], cos[0] * rad[stack + 1]);
				GL.Normal3(normal);
				GL.TexCoord2(1, yTextureTop);
				GL.Vertex3(sin[0] * radiusTop, yTop, cos[0] * radiusTop);
				GL.End();
			}
		}

		public static void Cube() { Cube(1.0); }
		public static void Cube(double size)
		{
			// some faces are not drawn correctly to be used with face culling
			double halfSize = size / 2.0;
			GL.Begin(BeginMode.Quads);

			int x = 2;
			int y = 3;

			double baseX = x / 16.0;
			double baseY = y / 16.0;

			Vector3d a, b, c, d;

			// front
			a = new Vector3d(-halfSize, -halfSize, halfSize);
			b = new Vector3d(halfSize, -halfSize, halfSize);
			c = new Vector3d(halfSize, halfSize, halfSize);
			d = new Vector3d(-halfSize, halfSize, halfSize);
			Normal(a, b, c);
			//GL.TexCoord2(baseX, baseY + 1 / 16.0);
			GL.Vertex3(a);
			//GL.TexCoord2(baseX + 1 / 16.0, baseY + 1 / 16.0);
			GL.Vertex3(b);
			//GL.TexCoord2(baseX + 1 / 16.0, baseY);
			GL.Vertex3(c);
			//GL.TexCoord2(baseX, baseY);
			GL.Vertex3(d);

			// back
			a = new Vector3d(-halfSize, -halfSize, -halfSize);
			b = new Vector3d(-halfSize, halfSize, -halfSize);
			c = new Vector3d(halfSize, halfSize, -halfSize);
			d = new Vector3d(halfSize, -halfSize, -halfSize);
			Normal(a, b, c);
			//GL.TexCoord2(baseX + 1 / 16.0, baseY + 1 / 16.0);
			GL.Vertex3(a);
			//GL.TexCoord2(baseX + 1 / 16.0, baseY);
			GL.Vertex3(b);
			//GL.TexCoord2(baseX, baseY);
			GL.Vertex3(c);
			//GL.TexCoord2(baseX, baseY + 1 / 16.0);
			GL.Vertex3(d);

			// right
			a = new Vector3d(halfSize, -halfSize, halfSize);
			b = new Vector3d(halfSize, -halfSize, -halfSize);
			c = new Vector3d(halfSize, halfSize, -halfSize);
			d = new Vector3d(halfSize, halfSize, halfSize);
			Normal(a, b, c);
			//GL.TexCoord2(baseX, baseY + 1 / 16.0);
			GL.Vertex3(a);
			//GL.TexCoord2(baseX + 1 / 16.0, baseY + 1 / 16.0);
			GL.Vertex3(b);
			//GL.TexCoord2(baseX + 1 / 16.0, baseY);
			GL.Vertex3(c);
			//GL.TexCoord2(baseX, baseY);
			GL.Vertex3(d);

			// left
			a = new Vector3d(-halfSize, -halfSize, halfSize);
			b = new Vector3d(-halfSize, halfSize, halfSize);
			c = new Vector3d(-halfSize, halfSize, -halfSize);
			d = new Vector3d(-halfSize, -halfSize, -halfSize);
			Normal(a, b, c);
			//GL.TexCoord2(baseX + 1 / 16.0, baseY + 1 / 16.0);
			GL.Vertex3(a);
			//GL.TexCoord2(baseX + 1 / 16.0, baseY);
			GL.Vertex3(b);
			//GL.TexCoord2(baseX, baseY);
			GL.Vertex3(c);
			//GL.TexCoord2(baseX, baseY + 1 / 16.0);
			GL.Vertex3(d);

			// top
			a = new Vector3d(-halfSize, halfSize, halfSize);
			b = new Vector3d(halfSize, halfSize, halfSize);
			c = new Vector3d(halfSize, halfSize, -halfSize);
			d = new Vector3d(-halfSize, halfSize, -halfSize);
			Normal(a, b, c);
			//GL.TexCoord2(baseX, baseY + 1 / 16.0);
			GL.Vertex3(a);
			//GL.TexCoord2(baseX + 1 / 16.0, baseY + 1 / 16.0);
			GL.Vertex3(b);
			//GL.TexCoord2(baseX + 1 / 16.0, baseY);
			GL.Vertex3(c);
			//GL.TexCoord2(baseX, baseY);
			GL.Vertex3(d);

			// bottom
			a = new Vector3d(-halfSize, -halfSize, halfSize);
			b = new Vector3d(-halfSize, -halfSize, -halfSize);
			c = new Vector3d(halfSize, -halfSize, -halfSize);
			d = new Vector3d(halfSize, -halfSize, halfSize);
			Normal(a, b, c);
			//GL.TexCoord2(baseX + 1 / 16.0, baseY + 1 / 16.0);
			GL.Vertex3(a);
			//GL.TexCoord2(baseX + 1 / 16.0, baseY);
			GL.Vertex3(b);
			//GL.TexCoord2(baseX, baseY);
			GL.Vertex3(c);
			//GL.TexCoord2(baseX, baseY + 1 / 16.0);
			GL.Vertex3(d);
			GL.End();
		}
	}
}
